package com.example.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * BeanFactoryPostProcessor可以对bean的定义（配置元数据）进行处理。
 * 也就是说，Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据，并有可能修改它。
 * 你可以配置多个BeanFactoryPostProcessor。你还能通过设置'order'属性来控制BeanFactoryPostProcessor的执行次序。
 */
@Component
public class BeanFactoryPostProcessorTest implements BeanFactoryPostProcessor {

    Set<String> RootBeanDefinitionSet = new HashSet<>();
    Set<String> GenericBeanDefinitionSet = new HashSet<>();
    Set<String> AnnotatedGenericBeanDefinitionSet = new HashSet<>();
    Set<String> ScannedGenericBeanDefinitionSet = new HashSet<>();
    Set<String> ConfigurationClassBeanDefinitionSet = new HashSet<>();

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {

            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            Object source = beanDefinition.getSource();
            if (source != null) {
                if (source instanceof FileSystemResource) {
                } else if (source instanceof MethodMetadata) {
                }
            }

            String className = beanDefinition.getClass().getName();
            boolean isRootBeanDefinition = className.equals(RootBeanDefinition.class.getName());
            if (isRootBeanDefinition) {
                RootBeanDefinitionSet.add(beanDefinitionName);
                System.out.println("RootBeanDefinition: " + beanDefinitionName);
            }
            // xml 解析标记
            boolean isGenericBeanDefinition = className.equals(GenericBeanDefinition.class.getName());
            if (isGenericBeanDefinition) {
                GenericBeanDefinitionSet.add(beanDefinitionName);
                System.out.println("GenericBeanDefinition: " + beanDefinitionName);
            }
            // @Import 导入的 Configuration Class 会解析成该对象
            // @Configuration + @ImportResource
            boolean isAnnotatedGenericBeanDefinition = className.equals(AnnotatedGenericBeanDefinition.class.getName());
            if (isAnnotatedGenericBeanDefinition) {
                AnnotatedGenericBeanDefinitionSet.add(beanDefinitionName);
                System.out.println("AnnotatedGenericBeanDefinition: " + beanDefinitionName);
            }
            // @Component 及派生注解、扫描包的方式，@Service、@Controller、单独使用@Configuration
            boolean isScannedGenericBeanDefinition = className.equals(ScannedGenericBeanDefinition.class.getName());
            if (isScannedGenericBeanDefinition) {
                ScannedGenericBeanDefinitionSet.add(beanDefinitionName);
                System.out.println("ScannedGenericBeanDefinition: " + beanDefinitionName);
            }

            // @Bean 标记的方法、FactoryBean（accessorFactoryBean）
            if (className.contains("$ConfigurationClassBeanDefinition")) {
                ConfigurationClassBeanDefinitionSet.add(beanDefinitionName);
                System.out.println("$ConfigurationClassBeanDefinition: " + beanDefinitionName);
            }
        }
        System.out.println();
    }
}
